3.1-gin 的使用
Create by fall on 03 Nov 2025 Recently revised in 06 Nov 2025
gin
非官方模块,类似于 node 的 express
请求相关
前置内容
之后的示例内容都默认引入该内容
package models
import "gorm.io/gorm"
// 前置内容,之后的内容都默认引入该内容
type Word struct {
gorm.Model
// Word 首字母必须大写 string 表示类型, json:"word" 表示对应 JSON 中的字段
Word string `json:"word"`
Accent string `json:"accent"`
Translate string `json:"translate,omitempty"` // omitempty 表示如果为空则省略
Example string `json:"example"`
}
param
路径参数
import (
"github.com/gin-gonic/gin"
)
func Handler(c *gin.Context) {
// 读取 Body 内容
userID := c.Param("id")
}
query
查询字符串中的数据 /path?name=fall
import (
"github.com/gin-gonic/gin"
)
func Handler(c *gin.Context) {
// 读取查询字符串
param := c.Query("param")
name := c.DefaultQuery("name", "fall")
// 读取查询字符串
mapt := c.QueryMap("filter")
var query Word
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
}
body
请求体中,Body 是一个 io.ReadCloser 流,意味着它只能被读取一次。如果仍想访问原始 Body(例如 ShouldBindJSON),必须使用 c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) 将其重置。
如果请求 Body 非常大(如文件上传),一次性读取到内存(ioutil.ReadAll)可能消耗大量资源。对于大文件,应考虑流式处理。
优先使用 Binding:对于结构化的数据(如 JSON、XML),推荐优先使用 ShouldBindXXX 系列方法
text-body
如果传入的是文本,解析文本
import (
"bytes"
"io/ioutil"
"github.com/gin-gonic/gin"
)
func Handler(c *gin.Context) {
// 读取 Body 内容
bodyBytes, err := ioutil.ReadAll(c.Request.Body)
// bodyBytes, err := c.GetRawData() // 效果等同于 ioutil.ReadAll(c.Request.Body)
if err != nil {
// 处理错误
c.JSON(400, gin.H{"error": "Failed to read request body"})
return
}
defer c.Request.Body.Close() // 确保 Body 关闭
// 将 Body 内容转换为字符串
bodyString := string(bodyBytes)
// 其它处理逻辑
c.JSON(200, gin.H{"received": bodyString})
}
json-body
如果传入的是 JSON 格式文件,可以使用
import (
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin"
)
func Handler(c *gin.Context) {
var req models.
if err := c.ShouldBindWith(req, binding.JSON); err != nil && err.Error() != "EOF" {
responses.ClientErrDetail(c, "解析请求体失败", err.Error())
return false
}
}
func PostHandler(c *gin.Context) {
var req Person
data, err := c.ShouldBindJSON()
if err != nil {
log.Fatal("获取数据失败", err)
return
}
var person Person
err2 := json.Unmarshal([]byte(data), &person)
if err2 != nil {
log.Fatal("解析 JSON 失败:", err)
}
}
formData
适用于 application/x-www-form-urlencoded 或 multipart/form-data
package routes
import (
"net/http"
"github.com/gin-gonic/gin"
)
func AddWord(c *gin.Context) {
word := new(Word)
// 读取 formData 数据
word.Word = c.PostForm("word")
word.Accent = c.PostForm("accent")
word.Translate = c.PostForm("translate")
word.Example = c.PostForm("example")
city := c.DefaultPostForm("city", "Beijing")
Println("receiving data ",word)
}
header
请求头内容
package routes
import (
"net/http"
"github.com/gin-gonic/gin"
)
func AddWord(c *gin.Context) {
token := c.Request.Header.Get("Authorization")
contentType := c.Request.Header.Get("Content-Type")
}
返回相关
import (
"github.com/gin-gonic/gin"
)
func AddWord(c *gin.Context) {
c.Status(200)
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": "创建成功",
})
}
中间件
func RequestLoggerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 只记录特定 Content-Type 的 Body,比如 JSON 或文本
if c.Request.Header.Get("Content-Type") == "application/json" {
bodyBytes, _ := c.GetRawData()
if len(bodyBytes) > 0 {
// 记录 Body 内容(生产环境中你可能想用 debug 级别或其他方式记录)
log.Printf("Request Body: %s", string(bodyBytes))
// 关键:将 Body 重新写回,以便后续绑定操作使用
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
}
}
c.Next() // 继续处理请求
}
}
// 在 Gin 中使用中间件
func main() {
r := gin.Default()
r.Use(RequestLoggerMiddleware()) // 注册全局中间件
r.POST("/login", LoginHandler) // 假设 LoginHandler 使用了 ShouldBindJSON
r.Run(":8080")
}
工具
读取传入的 json 文件,并且解析
解析 json
package utils
import (
"io"
"github.com/gin-gonic/gin"
)
func ReadFileJSON(c *gin.Context) []byte {
file, err := c.FormFile("json_file")
if err != nil {
c.JSON(400, gin.H{
"msg": "请上传 JSON 文件",
"detail": err.Error(),
})
}
openedFile, err := file.Open()
if err != nil {
c.JSON(500, gin.H{
"msg": "无法打开的 JSON 文件",
"detail": err.Error(),
})
}
defer openedFile.Close()
content, err := io.ReadAll(openedFile)
if err != nil {
c.JSON(500, gin.H{
"msg": "无法读取文件内容",
"err": err.Error(),
})
}
return content
}
查询参数处理
func GetIntQuery(c *gin.Context, key string, defaultValue int) int {
valueStr := c.Query(key)
if valueStr == "" {
return defaultValue
}
value, err := strconv.Atoi(valueStr)
if err != nil {
return defaultValue
}
return value
}
func GetBoolQuery(c *gin.Context, key string, defaultValue bool) bool {
valueStr := c.Query(key)
if valueStr == "" {
return defaultValue
}
value, err := strconv.ParseBool(valueStr)
if err != nil {
return defaultValue
}
return value
}